package com.koron.common.core.business.workflow.templates;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.koron.bean.app.AppBean;
import com.koron.bean.base.Response;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.bean.util.ServletUtils;
import com.koron.bean.workflow.*;
import com.koron.common.core.business.message.bean.po.MessageTemplatePo;
import com.koron.common.core.business.workflow.bean.constant.WorkflowConstant;
import com.koron.common.core.business.workflow.bean.po.SysWorkflow;
import com.koron.common.core.business.workflow.bean.properties.WorkFlowConfigProperties;
import com.koron.common.core.business.workflow.bean.result.DefineResult;
import com.koron.common.core.business.workflow.feign.CallerService;
import com.koron.common.core.business.workflow.feign.OrderOAFeignService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.StringUtils;
import com.koron.common.core.util.message.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * @author jzp
 * @since 2021/5/27 14:51
 */
@Slf4j
@Component
public class SysWorkflowAware {

    @Autowired
    private WorkFlowConfigProperties workFlowConfigProperties;

    @Autowired
    private CallerService callerService;

    @Autowired
    private MessageUtil messageUtil;


    private final ExecutorService service = new ThreadPoolExecutor(
            5,
            10,
            5000,
            TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1024),
            new CustomizableThreadFactory("sendMsgPoolService-"),
            new ThreadPoolExecutor.AbortPolicy());

    private final ExecutorService poolService = new ThreadPoolExecutor(
            5,
            10,
            5000,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1024),
            new CustomizableThreadFactory("sendUsersToOaPoolService-"),
            new ThreadPoolExecutor.AbortPolicy());

    public Response<Object> redirectUpdateState(String callbackPrefix, SysWorkflow sysWorkflow, SubmitQuery submitQuery) {
        RedirectQuery redirectQuery = new RedirectQuery();
        BeanUtils.copyProperties(submitQuery, redirectQuery);
        redirectQuery.setBillId(sysWorkflow.getBillId());
        redirectQuery.setCurNodeCode(sysWorkflow.getCurNodeCode());
        redirectQuery.setCurNodeName(sysWorkflow.getCurNodeName());

        callbackPrefix = enhanceCallbackPrefix(callbackPrefix) + "/";
        if (sysWorkflow.getCurNodeCode().equals("END")) {
            callbackPrefix += WorkflowController.endPath;
        } else if (sysWorkflow.getCurNodeCode().equals("CANCEL")) {
            callbackPrefix += WorkflowController.cancelPath;
        } else {
            callbackPrefix += WorkflowController.statePath;
        }
        log.info("流程回调业务状态处理。URL：{}，参数：{}", callbackPrefix, JSONObject.toJSONString(submitQuery));
        return callerService.updateStatus(callbackPrefix, redirectQuery);
    }

    public Response<List<WorkflowUser>> redirectListWorkflowUser(String callbackPrefix, SubmitterParam submitterParam) {
        callbackPrefix = enhanceCallbackPrefix(callbackPrefix);
        log.info("流程回调插件人员信息。URL：{}，参数：{}，", callbackPrefix, JSONObject.toJSONString(submitterParam));
        return callerService.listWorkflowUser(callbackPrefix, submitterParam);
    }

    /**
     * 拼接请求路径前缀
     */
    private String enhanceCallbackPrefix(String callbackPrefix) {
        if (callbackPrefix.startsWith("http")) {
            return callbackPrefix;
        }
        HttpServletRequest request = ServletUtils.getRequest();
        String home = workFlowConfigProperties.getHome();
        if (!StringUtils.isEmpty(home)) {
            return home + "/" + callbackPrefix;
        }
        return request.getScheme() + "://" + request.getServerName() + ":30001/" + callbackPrefix;
    }

    /**
     * 通知OA待办数量
     */
    public void sendUsersToOa(SysWorkflow sysWorkflowBefore, SysWorkflow sysWorkflowAfter) {
        String[] strings1 = Optional.ofNullable(sysWorkflowBefore)
                .map(SysWorkflow::getCurNodeUserId)
                .map(e -> e.split(","))
                .orElse(new String[]{ThreadLocalContext.get().getAccount()});

        String[] strings2 = Optional.ofNullable(sysWorkflowAfter)
                .map(SysWorkflow::getCurNodeUserId)
                .map(e -> e.split(","))
                .orElse(new String[]{});
        List<String> result = Stream.concat(Arrays.stream(strings1), Arrays.stream(strings2)).distinct().collect(Collectors.toList());
        log.info("更新代办数量人员列表:{}", JSON.toJSONString(result));
        poolService.execute(() -> {
            try {
                OrderOAFeignService orderOAFeignService = SpringUtil.getBean(OrderOAFeignService.class);
                orderOAFeignService.sendUsersToOa(result);
            } catch (Exception e) {
                log.error(e.getMessage());
            } finally {
                ThreadLocalContext.clear(); // 清除tl
            }
        });
    }

    /**
     * 发送通知
     */
    public void sendMsg(SysWorkflow sysWorkflowBefore, SysWorkflow sysWorkflowAfter, DefineResult defineResult, SubmitQuery submitQuery) {
        AtomicBoolean sendFailStatus = new AtomicBoolean(false);
        AtomicReference<String> topicAccount = new AtomicReference<>();
        AtomicReference<String> topicContent = new AtomicReference<>();
        EamUser eamUser = ThreadLocalContext.get();
        AppBean appBean = ThreadLocalContext.getApp();
        log.info("SysWorkflowAware:sendMsg:eamUser={},appBean={}",eamUser,appBean);
        try {
            log.info("发送通知！");
            service.execute(() -> {
                ThreadLocalContext.set(eamUser);
                ThreadLocalContext.setApp(appBean);
                log.info("SysWorkflowAware:sendMsg:sysWorkflowBefore={},sysWorkflowAfter={},defineResult={},submitQuery={}"
                        , sysWorkflowBefore, sysWorkflowAfter, defineResult, submitQuery);
                try {
                    // 接收人
                    String receiver = submitQuery.getOperation() == 2 || submitQuery.getOperation() == 4 ? submitQuery.getRelatedUser() : sysWorkflowAfter.getCurNodeUserId();
                    String noticeWay = defineResult.getNoticeWay();
                    String example = WorkflowConstant.getExample(submitQuery.getOperation(), sysWorkflowBefore == null ? ThreadLocalContext.get().getName() : sysWorkflowBefore.getCurNodeUserName(), sysWorkflowAfter.getCurNodeUserName(), sysWorkflowAfter.getTitle());
                    topicAccount.set(receiver);
                    topicContent.set(example);
                    log.info("SysWorkflowAware:receiver={},noticeWay={},example={}", receiver, noticeWay, example);
                    List<MessageTemplatePo> workflow_audit = messageUtil.getTemplate("workflow_audit");
                    log.info("SysWorkflowAware:workflow_audit={}", workflow_audit);
                    if (CollectionUtils.isEmpty(workflow_audit)) {
                        log.warn("找不到流程通知模板");
                        return;
                    }
                    // 只看已打开的通知方式
                    List<String> notifyTypes = workflow_audit.stream().filter(MessageTemplatePo::getStatus).map(MessageTemplatePo::getNotifyType).collect(Collectors.toList());
                    String eamRedirectHref = messageUtil.getRoutePath() + "upComingCenter/upComing";
                    String url = messageUtil.generateQywxHref(eamRedirectHref);
                    log.info("企业微信初始化链接{}", url);
                    // 使用待办1来表示企业微信
                    if (noticeWay.contains("1") && notifyTypes.contains("qywx")) {
                        try {
                            String eamHref = messageUtil.generateEamIdHref("transmit_" + sysWorkflowAfter.getProcessCode(), sysWorkflowAfter.getDataId());
                            eamRedirectHref = messageUtil.generateEamRedirectHref(eamHref);
                            url = messageUtil.generateQywxHref(eamRedirectHref);
                            log.info("企业微信发送链接{}", url);
                            example = example + " | <a href=\"" + url + "\">传送门>></a>";
                            messageUtil.sendQywxText("workflow_audit", receiver, example);
                        } catch (Exception e) {
                            sendFailStatus.set(true);
                            log.info("SysWorkflowAware:sendMsg:error:example={},eamRedirectHref={},url={}", example, eamRedirectHref, url);
                            log.error(e.getMessage());
                        }
                    }
                    if (noticeWay.contains("2")) {
                        // 邮件2
                    }
                    if (noticeWay.contains("4") && notifyTypes.contains("sms")) {
                        // 短信4
                        example = "设备资产|" + example;
                        messageUtil.sendSms("workflow_audit", receiver, example);
                    }
                    log.info("通知内容：" + example);
                } catch (Exception e) {
                    sendFailStatus.set(true);
                    log.error(e.getMessage());
                } finally {
                    ThreadLocalContext.clear(); // 清除tl
                }
                if (sendFailStatus.get()){
                    messageUtil.sendQywxText("workflow_audit", topicAccount.get(), topicContent.get());
                }
            });
        } catch (Exception e) {
            ThreadPoolExecutor tpe = (ThreadPoolExecutor) service;
            log.error("ThreadPoolExecutor:service:当前活动线程数={},当前排队线程数={},执行完成线程数={},总线程数={}", tpe.getActiveCount(), tpe.getQueue().size(), tpe.getCompletedTaskCount(), tpe.getTaskCount());
        }
    }

    @Deprecated
    public void sendMsg(String noticeWay, Integer operator, String beforeUser, String afterUser, String title, String processCode, String dataId, String account) {
        service.execute(() -> {
            try {
                String example = WorkflowConstant.getExample(operator, beforeUser, afterUser, title);
                String eamRedirectHref = messageUtil.getRoutePath() + "upComingCenter/upComing";
                String url = messageUtil.generateQywxHref(eamRedirectHref);
                // 使用待办1来表示企业微信
                if (noticeWay.contains("1")) {
                    try {
                        String eamHref = messageUtil.generateEamIdHref("transmit_" + processCode, dataId);
                        eamRedirectHref = messageUtil.generateEamRedirectHref(eamHref);
                        url = messageUtil.generateQywxHref(eamRedirectHref);
                        example = example + " | <a href=\"" + url + "\">传送门>></a>";
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    }
                    messageUtil.sendQywxText("workflow_audit", account, example);
                }
                if (noticeWay.contains("2")) {
                    // 邮件2
                }
                if (noticeWay.contains("4")) {
                    // 短信4
                    example = "设备资产|" + example;
                    messageUtil.sendSms("workflow_audit", account, example);
                }
                log.info("通知内容：" + example);
            } catch (Exception e) {
                log.error(e.toString());
            } finally {
                ThreadLocalContext.clear(); // 清除tl
            }
        });
    }
}
